# PDB exception handling
from ZenExceptions import ZenConstructionError, ZenConstructionWarning

# SMCRA hierarchy
from Entities import Structure, Model, Chain, Residue, Atom
from Holders import AtomHolder

class StructureBuilder(object):
    """ Deals with contructing the Structure object. The StructureBuilder class is used
    by the PDBParser classes to translate a file to a Structure object.
    """
    hierarchy = ['S','M','C','R','A']

    def __init__(self):
        self.structure = None

    def init_structure(self, structure_id):
        self.structure = Structure(structure_id)

    def init_model(self, model_id):
        if not (model_id,) in self.structure:
            self.model = Model(model_id)
            if model_id != 0:
                self.model.set_masked(True)
            self.model.junk = AtomHolder('junk')
            self.structure._init_child(self.model)
        else:
            raise ZenConstructionError

    def init_chain(self, chain_id):
        if not (chain_id,) in self.model:
            self.chain = Chain(chain_id)
            self.model._init_child(self.chain)
        else:
            self.chain = self.model[(chain_id,)]
            #print 'Warning: Chain %s is not continous' % chain_id
            raise ZenConstructionWarning

    def init_seg(self, seg_id):
        self.seg_id = seg_id

    def init_residue(self, res_long_id, res_name):
        if not (res_long_id,) in self.chain:
            self.residue = Residue(res_long_id, res_name, self.seg_id)
            self.chain._init_child(self.residue)
        else:
            self.residue = self.chain[(res_long_id,)]
            print 'Warning: Residue %s%s%s is not continous' % res_long_id
            raise ZenConstructionWarning

    def init_atom(self, at_long_id, at_name, ser_num, coord, occupancy, bfactor, element):
        if not (at_long_id,) in self.residue:
            self.atom = Atom(at_long_id, at_name, ser_num, coord, occupancy, bfactor, element)
            self.residue._init_child(self.atom)
        else:
            print 'Error: Atom %s%s defined twice' % at_long_id
            full_id = (tuple(self.residue[(at_long_id,)].get_full_id()), ser_num)
            self.model.junk._init_child(Atom(full_id, at_name, ser_num, coord, occupancy, bfactor, element))
            raise ZenConstructionError

    def get_structure(self):
        """ Return the structure.
        """
        # finalize the structure on leave
        self.structure.set_table()
        self.structure.recursive_set_coords()
        return self.structure

#EOF